package yxy.cherry.game;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.ParserConfig;
import org.joda.time.DateTime;
import org.redisson.api.RBucket;
import org.redisson.api.RMap;
import yxy.apple.database.DAOAccountManager;
import yxy.apple.database.DAOGameManager;
import yxy.apple.db.DbManager;
import yxy.apple.logger.Logger;
import yxy.apple.util.RuntimeUtility;
import yxy.apple.util.RuntimeUtility.ShutdownHookable;
import yxy.apple.util.concurrent.ThreadPoolManager;
import yxy.apple.util.redisson.FastjsonCodec;
import yxy.apple.util.redisson.RedisConnection;
import yxy.apple.util.redisson.RedisException;
import yxy.banana.launcher.JSONBeanConfiguration;
import yxy.cherry.battle.module.affix.AffixFactory;
import yxy.cherry.battle.module.selector.TargetSelectorFactory;
import yxy.cherry.data.DataCenter;
import yxy.cherry.data.actdata.DataCenterAct;
import yxy.cherry.data.dfa.Sensitive;
import yxy.cherry.data.script.FomulaScript;
import yxy.cherry.game.base.module.IGameModule;
import yxy.cherry.game.base.mq.MqManager;
import yxy.cherry.game.base.redis.RedisManager;
import yxy.cherry.game.base.redis.RedisType;
import yxy.cherry.game.message.ConsumerImpl;
import yxy.cherry.game.message.MessageDispatcher;
import yxy.game.pm2.bean.area.AreaBean;
import yxy.game.pm2.module.mail.MailBean;

import java.util.*;

import static yxy.cherry.data.DataCenter.getAllData;

public class Game {
    public static String ApplicationName = "Game";
    public static String ReleaseVersion = "1.0-SNAPSHOT";
    public static String ReleaseDate = "20200801";
    public static String Slogan = " -= " + ApplicationName + " V" + ReleaseVersion + " Release " + ReleaseDate + " =-";

    protected static Logger logger = Logger.create(Game.class);

    private static class Cleaner implements ShutdownHookable {
        @Override
        public void shutting() {
            logger.info("正在关闭%s...", ApplicationName);
            RedisManager.getInstance().disconnect();
            Reactor.instance.shutdown();
            logger.info("完成%s全部关闭工作，Bye!", ApplicationName);
        }
    }

    public void start() {
        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
        try {
            logger.info(Slogan);
            logger.info("正在启动...");
            logger.info("正在载入配置...");
            Configuration config = initConfig();

            logger.info("设置日志等级为%s", config.LogLevel.name());
            Logger.setLevel(config.LogLevel);
            logger.info("加载逻辑服消息处理集...");
            initCommand();
            logger.info("正在添加ShutdownHook服务...");
            RuntimeUtility.addShutdownHook(new Cleaner());
            logger.info("正在初始化Redis连接...");
            initRedis(config);
            logger.info("正在初始化Redis配置...");
            RedisConfiguration redisConfig = initRedisConfig();
            logger.info("正在初始化MQ连接...");
            initMQ(config);
            logger.info("正在初始化数据库连接...");
            DAOAccountManager.init(config.DBAccountConfig);
            logger.info("正在初始化数据库连接...");
            DAOGameManager.init(config.DBGameConfig);
            logger.info("正在GAME数据库连接...");
            initMysql(redisConfig);
            logger.info("正在初始化线程池...");
            initThreadPool(redisConfig);

            Reactor.instance.start(config);

            logger.info("添加消息消费者...");
            initConsumer(config);

            logger.info("正在清理系统邮件...");
            clearSysMail();

            logger.info("%s服务器启动完成!", ApplicationName);

        } catch (Exception e) {
            logger.error(e);
            System.exit(5);
        }
    }

    private Configuration initConfig() throws Exception {
        Configuration config = null;
        String outsideConfig = null;
// XXX 屏蔽Lagos
//		try {
//			ConfigChangeManager configChangeManager = new ConfigChangeManager();
//			configChangeManager.addSubcribe();
//			outsideConfig = Lagos.getInstance().load();
//		} catch (Exception e) {
//			logger.error("读取外部配置文件失败", e);
//			outsideConfig = null;
//		}
        if (outsideConfig == null) {
            String filename = System.getProperty("user.dir") + "/config.json";
            logger.info("加载配置文件%s...", filename);
            config = JSONBeanConfiguration.load(filename, Configuration.class);
//XXX 屏蔽Lagos
//		} else {
//			logger.info("加载nacos配置\n%s", outsideConfig);
//			config = JSONBeanConfiguration.load(JSONObject.parseObject(outsideConfig), Config.class);
        }

        JSONBeanConfiguration.share(Configuration.SharedKey, config);
        return config;
    }

    private RedisConfiguration initRedisConfig() throws Exception {
        RedisConnection connection = RedisManager.getInstance().getConnection(RedisType.REDIS_DATA);
        RBucket<JSONObject> rbucket = connection.client().getBucket("CONFIG");
        JSONObject jsonObject = rbucket.get();
        return JSONBeanConfiguration.load(jsonObject, RedisConfiguration.class);
    }

    private void initMysql(RedisConfiguration config) {
        DbManager.instance().init(config.dbConfig);
    }

    private void initThreadPool(RedisConfiguration config) {
        ThreadPoolManager.getInstance().start(config.threadPool);
    }

    private void initMQ(Configuration config) throws Exception {
        MqManager.getInstance().init(config.MqConfig);
    }

    private void initRedis(Configuration config) throws Exception {
        {
            RedisConnection redisUser = new RedisConnection();
            redisUser.connect(config.UserRedis.Address, config.UserRedis.Password, config.UserRedis.Database, true, new FastjsonCodec());
            RedisManager.getInstance().addConnection(RedisType.REDIS_USER, redisUser);
        }
        {
            RedisConnection redisGame = new RedisConnection();
            redisGame.connect(config.GameRedis.Address, config.GameRedis.Password, config.GameRedis.Database, true, new FastjsonCodec());
            RedisManager.getInstance().addConnection(RedisType.REDIS_GAME, redisGame);
        }
        {
            RedisConnection redisData = new RedisConnection();
            redisData.connect(config.DataRedis.Address, config.DataRedis.Password, config.DataRedis.Database, true, new FastjsonCodec());
            RedisManager.getInstance().addConnection(RedisType.REDIS_DATA, redisData);

            DataCenter.init(redisData, false);

            //初始化敌方英雄数据
            initProperty();

            FomulaScript.init(redisData);
            Sensitive.init(redisData);
        }
        {
            TargetSelectorFactory.getInstance();
            AffixFactory.getInstance();

            initDataCenterAct();
        }
    }

    private void initDataCenterAct() {
        Collection<AreaBean> abs = AreaBean.all();
        ArrayList<Integer> areaids = new ArrayList<Integer>();
        for (AreaBean ab : abs) {
            areaids.add(ab.getAreaId());
        }

        DataCenterAct.init(RedisManager.getInstance().getConnection(RedisType.REDIS_DATA), false, areaids);
    }

    private void initCommand() throws Exception {
        // 根据游戏包提供的resurces/META-INF/services/yxy.cherry.game.base.module.IGameModule文件内容获取IGameModule子类
        // 每个游戏包都需要提供响应的IGameModule实现来定位其Message和Command包地址
        ServiceLoader<IGameModule> serviceLoaders = ServiceLoader.load(IGameModule.class);
        if (!serviceLoaders.iterator().hasNext()) {
            logger.error("游戏包加载失败，请检查pom配置");
            throw new Exception("IGameModule is empty");
        }
        for (IGameModule gameModule : serviceLoaders) {
            gameModule.init();
            MessageDispatcher.getInstance().initMessage(gameModule);
        }
    }

    private void initConsumer(Configuration config) {
        // 配置消费者线程，需要根据config里配置的数量来定义消费者数量
        for (int i = config.MessageStationThreads; i > 0; i--) {
            Reactor.instance.station().treat(new ConsumerImpl());
        }
//		System.out.println(Thread.getAllStackTraces().size());
    }

    private void clearSysMail() {
        try {
            Collection<AreaBean> collection = AreaBean.all();
            for (AreaBean areaBean : collection) {
                ArrayList<String> serverList = areaBean.getServerList();
                for (String areaId : serverList) {
                    RMap<String, MailBean> sysMail = MailBean.touchSysMail(Integer.parseInt(areaId));
                    if (sysMail.size() == 0) {
                        return;
                    }
                    for (String s : sysMail.keySet()) {
                        MailBean mailBean = sysMail.get(s);
                        if (DateTime.now().isAfter(mailBean.getExpiryTime())) {
                            MailBean.delSysMail(Integer.parseInt(areaId), s);
                        }
                    }
                }
            }
        } catch (RedisException ex) {
            ex.printStackTrace();
        }
    }

    private void initProperty() {

        //初始化  FighterModule

    }




    public static void main(String[] args) {
        new Game().start();
    }
}
